/*********************\
* Author:Dzlua
* QQ:505544956
* Time:2017/04/09
\**********************/
#include "LuaHelper.h"

namespace DuiLib {
namespace LuaHelper {

void Register(LuaState *L)
{
    L->GetGlobals().CreateTable("__metatables__");
    L->GetGlobals().CreateTable("__objects__");
}

void UnRegister(LuaState *L)
{
    L->GetGlobals().SetNil("__objects__");
    L->GetGlobals().SetNil("__metatables__");
}

//=====================================================//
//get the table where save Luaclass metatable
LuaObject GetTableOfMetas(LuaState *L)
{
    return L->GetGlobals()["__metatables__"];
}

//create a table to saved Luaclass metatables.return the table.
LuaObject AddToMetas(LuaState *L, const char* key, const char* parent)
{
    LuaObject obj = GetTableOfMetas(L).CreateTable(key);
    if (parent){
        obj.SetMetaTable(GetFromMetas(L, parent));
    }
    return obj;
}

//add the table from save Luaclass metatables
LuaObject GetFromMetas(LuaState *L, const char* key)
{
    return GetTableOfMetas(L)[key];
}

//remove the table from save Luaclass metatables
void RemoveFromMetas(LuaState *L, const char* key)
{
    GetTableOfMetas(L).SetNil(key);
}

//=====================================================//
//get the table where save Luaclass objects
LuaObject GetTableOfObjs(LuaState *L)
{
    return L->GetGlobals()["__objects__"];
}

//create a table to saved Luaclass objects.return the table.
LuaObject AddToObjs(LuaState *L, void* key)
{
    return GetTableOfObjs(L).CreateTable((int)key);
}

//get the table from save Luaclass objects
LuaObject GetFromObjs(LuaState *L, void* key)
{
    return GetTableOfObjs(L)[(int)key];
}

//remove the table from save Luaclass objects
void RemoveFromObjs(LuaState *L, void* key)
{
    GetTableOfObjs(L).SetNil((int)key);
}

//=====================================================//
//add a event to Objs
bool SetEventToObjs(LuaState *L, void* key, const char* evtname, LuaObject event)
{
    if (!evtname || !event.IsFunction()) return false;
    LuaObject obj = GetFromObjs(L, key);
    if (obj.IsNil()) return false;
    if (obj["__events__"].IsNil()) obj.CreateTable("__events__");
    obj["__events__"].SetObject(evtname, event);
    return true;
}

//get a event from Objs
LuaObject GetEventFromObjs(LuaState *L, void* key, const char* eventname)
{
    LuaObject obj = GetFromObjs(L, key);
    if (obj.IsNil()) return obj;
    obj = obj["__events__"];
    if (obj.IsNil()) return obj;
    return obj[eventname];
}

//remove the event from Objs
void RemoveEventFromObjs(LuaState *L, void* key, const char* eventname)
{
    LuaObject obj = GetFromObjs(L, key);
    if (obj.IsNil()) return;
    obj = obj["__events__"];
    if (obj.IsNil()) return;
    obj.SetNil(eventname);
}

//=====================================================//
//set a c++ pointer to table.
void SetCObject(LuaObject obj, LuaClassBase* cobj)
{
    if (obj.IsNil()) return;
    obj.SetLightUserData("__object", cobj);
}

//get the c++ pointer if had.
LuaClassBase* GetCObject(LuaObject obj)
{
    if (!obj.IsTable()) return 0;
    obj = obj["__object"];
    if (obj.IsNil()) return 0;
    return (LuaClassBase*)obj.GetLightUserData();
}

//get the c++ pointer's data
void* GetCObjectData(LuaObject obj)
{
    LuaClassBase* pCObj = GetCObject(obj);
    if (!pCObj) return 0;
    return pCObj->GetCObj();
}

//=====================================================//
SDTString GetTString(LuaObject obj, SDTString defaultstr)
{
#ifdef _UNICODE
    if (obj.IsWString()) {
        return ((LPCWSTR)obj.GetWString());
    }
#else
    if (obj.IsString()) {
        return ((LPCSTR)obj.GetString());
    }
#endif
    return defaultstr;
}

SDTChar GetTChar(LuaObject obj, TCHAR defvalue)
{
    SDTString str = GetTString(obj);
    if (!str.empty()) {
        return str.at(0);
    }
    return defvalue;
}

DWORD GetDWord(LuaObject obj, DWORD defvalue)
{
    return (DWORD)GetInt(obj, (int)defvalue);
}

int GetInt(LuaObject obj, int defvalue)
{
    if (obj.IsInteger()) {
        return obj.ToInteger();
    }
    return defvalue;
}

LONG GetLong(LuaObject obj, LONG defvalue)
{
    return (LONG)GetInt(obj, (int)defvalue);
}

unsigned int GetUInt(LuaObject obj, unsigned int defvalue)
{
    if (obj.IsInteger()) {
        return (unsigned int)obj.ToInteger();
    }
    return defvalue;
}

bool GetBool(LuaObject obj, bool defvalue)
{
    if (obj.IsBoolean()) {
        return obj.GetBoolean();
    }
    return defvalue;
}

LPVOID GetLPVoid(LuaObject obj, LPVOID defvalue)
{
    if (obj.IsLightUserData()) {
        return obj.GetLightUserData();
    }
    return defvalue;
}

RECT GetRect(LuaObject obj, int defvalue)
{
    RECT rc = { defvalue, defvalue, defvalue, defvalue };
    if (obj.IsTable()) {
        rc.left = GetInt(obj.GetByName("l"), defvalue);
        rc.top = GetInt(obj.GetByName("t"), defvalue);
        rc.right = GetInt(obj.GetByName("r"), defvalue);
        rc.bottom = GetInt(obj.GetByName("b"), defvalue);
    }
    return rc;
}

POINT GetPoint(LuaObject obj, int defvalue)
{
    POINT pt = { defvalue, defvalue };
    if (obj.IsTable()) {
        pt.x = GetInt(obj.GetByName("x"), defvalue);
        pt.y = GetInt(obj.GetByName("y"), defvalue);
    }
    return pt;
}

SIZE GetSize(LuaObject obj, int defvalue)
{
    SIZE sz = { defvalue, defvalue };
    if (obj.IsTable()) {
        sz.cx = GetInt(obj.GetByName("cx"), defvalue);
        sz.cy = GetInt(obj.GetByName("cy"), defvalue);
    }
    return sz;
}

int GetRollTextDirect(LuaObject obj, int defvalue)
{
    SDTString str = GetTString(obj);
    if (!str.empty()) {
        if (str == _T("left"))
            return ROLLTEXT_LEFT;
        else if (str == _T("right"))
            return ROLLTEXT_RIGHT;
        else if (str == _T("up"))
            return ROLLTEXT_UP;
        else if (str == _T("down"))
            return ROLLTEXT_DOWN;
    }
    return defvalue;
}

SYSTEMTIME GetSysTime(LuaObject obj)
{
    SYSTEMTIME st = { 0 };
    if (obj.IsTable()) {
        st.wYear = GetInt(obj.GetByName("year"), 0);
        st.wMonth = GetInt(obj.GetByName("month"), 0);
        st.wDay = GetInt(obj.GetByName("day"), 0);
        st.wHour = GetInt(obj.GetByName("hour"), 0);
        st.wMinute = GetInt(obj.GetByName("min"), 0);
        st.wSecond = GetInt(obj.GetByName("sec"), 0);
        st.wMilliseconds = GetInt(obj.GetByName("msec"), 0);
        st.wDayOfWeek = GetInt(obj.GetByName("wday"), 0);
    }
    return st;
}

//=====================================================//
void PushCObj(LuaState *L, void* data)
{
    LuaObject obj = LuaHelperNS::GetFromObjs(L, data);
    obj.Push();
}

void PushTString(LuaState *L, SDTString str)
{
#ifdef _UNICODE
    L->PushWString((const lua_WChar*)str.c_str());
#else
    L->PushString(str.c_str());
#endif
}

void PushTChar(LuaState *L, SDTChar val)
{
    SDTString str;
    str += val;
    PushTString(L, str);
}

void PushLPVoid(LuaState *L, LPVOID data)
{
    LuaObject obj;
    obj.AssignLightUserData(L, data);
    obj.Push();
}

void PushRect(LuaState *L, RECT &rc)
{
    LuaObject tab;
    tab.AssignNewTable(L);
    tab.SetInteger("l", rc.left);
    tab.SetInteger("t", rc.top);
    tab.SetInteger("r", rc.right);
    tab.SetInteger("b", rc.bottom);
    tab.Push();
}

void PushPoint(LuaState *L, POINT &pt)
{
    LuaObject tab;
    tab.AssignNewTable(L);
    tab.SetInteger("x", pt.x);
    tab.SetInteger("y", pt.y);
    tab.Push();
}

void PushSize(LuaState *L, SIZE &sz)
{
    LuaObject tab;
    tab.AssignNewTable(L);
    tab.SetInteger("cx", sz.cx);
    tab.SetInteger("cy", sz.cy);
    tab.Push();
}

void PushSysTime(LuaState *L, SYSTEMTIME &st)
{
    LuaObject tab;
    tab.AssignNewTable(L);
    tab.SetInteger("year", st.wYear);
    tab.SetInteger("month", st.wMonth);
    tab.SetInteger("day", st.wDay);
    tab.SetInteger("hour", st.wHour);
    tab.SetInteger("min", st.wMinute);
    tab.SetInteger("sec", st.wSecond);
    tab.SetInteger("msec", st.wMilliseconds);
    tab.SetInteger("wday", st.wDayOfWeek);
    tab.Push();
}

}
}